#! -*- coding:utf-8 -*-

from datetime import datetime

from common import orm
from common.account.db import account as account_db
from common.account.model.account import Account, BALANCE_TYPE
from common.platform.common.model import M_TRANSACTION_TYPE, ThirdTransaction, ThirdWithdrawTransactionLog
from common.platform.common.model import PLATFORM_TYPE
from common.platform.integrate import get_third_handler
from common.utils import track_logging
from common.utils.currency import convert_yuan_to_fen, convert_fen_to_yuan

_LOGGER = track_logging.getLogger(__name__)


def frozen_balance(user_id, platform, amount, ref_id):
    """
    冻结资金到第三方游戏平台

    :param user_id:
    :param platform:
    :param amount: 单位是分
    :param ref_id: 交易唯一订单号
    :return:
    """
    _LOGGER.info(
        'begin frozen_balance: uid: {}, platform: {}, amount: {}, ref_id: {}'.format(user_id, platform, amount, ref_id))
    assert user_id > 0
    assert platform in PLATFORM_TYPE.values()

    try:
        if amount <= 0:
            return
        account = Account.query.with_for_update().filter(Account.id == user_id).first()
        assert account.balance >= account.withdraw
        trans = get_transaction_by_ref_id(M_TRANSACTION_TYPE.FROZEN, ref_id)
        ori_balance = convert_yuan_to_fen(account.balance)
        ori_withdraw = convert_yuan_to_fen(account.withdraw)
        if trans:
            return trans
        account = account_db.decrease_balance(user_id, amount, BALANCE_TYPE.BALANCE)
        deposit_balance = ori_balance - convert_yuan_to_fen(account.balance)
        deposit_withdraw = ori_withdraw - convert_yuan_to_fen(account.withdraw)
        trans = add_transaction(user_id, platform, ref_id, M_TRANSACTION_TYPE.FROZEN, deposit_balance,
                                deposit_withdraw)

        _calc_current_amount(account, trans)
        orm.session.commit()
        _LOGGER.info('finish frozen_balance: {} {} {} {}'.format(user_id, platform, amount, ref_id))
        return trans
    except:
        orm.session.rollback()
        raise
    finally:
        orm.session.close()


def reverse_not_existed_fronzen(user_id, ref_id):
    """
    回滚 冻结资金到第三方游戏平台 操作.

    :param user_id:
    :param ref_id:
    :return: (boolean: 是否本次成功, reverse_trans: 冲正trans)
    """
    try:
        _LOGGER.info('begin reverse frozen_balance : {} {}'.format(user_id, ref_id))
        account = Account.query.with_for_update().filter(Account.id == user_id).first()
        deposit_trans = get_transaction_by_ref_id(M_TRANSACTION_TYPE.FROZEN, ref_id)
        if not deposit_trans:
            return
        reverse_trans = get_transaction_by_ref_id(M_TRANSACTION_TYPE.FROZEN_REVERSE, ref_id)
        if reverse_trans:
            return False, reverse_trans

        reverse_trans = add_transaction(user_id, deposit_trans.platform, ref_id, M_TRANSACTION_TYPE.FROZEN_REVERSE,
                                        -deposit_trans.balance, -deposit_trans.withdraw)
        account.balance += convert_fen_to_yuan(reverse_trans.balance)
        account.withdraw += convert_fen_to_yuan(reverse_trans.withdraw)

        _calc_current_amount(account, reverse_trans)
        orm.session.commit()
        _LOGGER.info('finish reverse frozen_balance: {} {}'.format(user_id, ref_id))
        return True, reverse_trans
    except:
        orm.session.rollback()
        raise
    finally:
        orm.session.close()


def unfreeze_balance(user_id, platform, amount, ref_id):
    """
    从第三方平台提现钱到loki

    :param user_id:
    :param platform:
    :param amount: 单位是分
    :param ref_id: 交易唯一订单号
    :return:
    """
    assert user_id > 0
    _LOGGER.info(
        'begin unfreeze_balance: uid: {}, platform: {}, amount: {}, ref_id: {}'.format(user_id, platform, amount,
                                                                                       ref_id))
    try:
        if amount <= 0:
            return
        account = Account.query.with_for_update().filter(Account.id == user_id).first()
        trans = get_transaction_by_ref_id(M_TRANSACTION_TYPE.UNFREEZE, ref_id)
        if trans:
            return trans
        trans = add_transaction(user_id, platform, ref_id, M_TRANSACTION_TYPE.UNFREEZE, amount, 0)
        account.balance += convert_fen_to_yuan(trans.balance)
        account.withdraw += convert_fen_to_yuan(trans.withdraw)

        _calc_current_amount(account, trans)
        orm.session.commit()
        _LOGGER.info('finish unfreeze_balance: {} {} {} {}'.format(user_id, platform, amount, ref_id))
        return trans
    except:
        orm.session.rollback()
        raise
    finally:
        orm.session.close()


def add_transaction(user_id, platform, ref_id, trans_type, balance, withdraw):
    assert user_id > 0
    assert platform in PLATFORM_TYPE.values()
    assert ref_id
    assert trans_type in M_TRANSACTION_TYPE.values()
    assert balance > 0
    assert withdraw >= 0
    assert balance or withdraw
    trans = ThirdTransaction()
    trans.platform = platform
    trans.user_id = user_id
    trans.ref_id = ref_id
    trans.type = trans_type

    last_trans = _get_latest_trans(user_id, platform)
    if trans_type == M_TRANSACTION_TYPE.FROZEN:
        assert balance >= withdraw
        balance = -balance
        withdraw = -withdraw
    elif trans_type == M_TRANSACTION_TYPE.FROZEN_REVERSE:
        pass
    elif trans_type == M_TRANSACTION_TYPE.UNFREEZE:
        last_frozen_trans = _get_latest_trans(user_id, platform, trans_type=M_TRANSACTION_TYPE.FROZEN)
        assert last_frozen_trans
        accu_win_amount = get_third_handler(platform).calculate_accumulated_win_amount(user_id,
                                                                                       last_frozen_trans.created_at,
                                                                                       datetime.utcnow())
        withdraw = min(accu_win_amount + -last_frozen_trans.withdraw, balance)
    else:
        raise Exception('trans type error')

    trans.balance = balance
    trans.withdraw = withdraw

    trans.accu_balance = (last_trans.accu_balance if last_trans else 0) + balance

    trans.save(auto_commit=False)
    orm.session.flush()
    return trans


def get_transaction_by_id(trans_id):
    assert trans_id > 0
    metis_trans = ThirdTransaction.query.filter_by(id=trans_id).order_by(ThirdTransaction.id.desc()).first()
    return metis_trans


def get_transaction_by_ref_id(trans_type, ref_id):
    assert trans_type in M_TRANSACTION_TYPE.values()
    assert ref_id
    metis_trans = ThirdTransaction.query.filter_by(type=trans_type, ref_id=ref_id).order_by(
        ThirdTransaction.id.desc()).first()
    return metis_trans


def add_withdraw_trans_log(user_id, platform, amount, ref_id):
    try:
        withdraw_trans_log = ThirdWithdrawTransactionLog(user_id=user_id, platform=platform, amount=amount, ref_id=ref_id)
        withdraw_trans_log.save()
        return withdraw_trans_log.id
    finally:
        orm.session.close()


def delete_withdraw_trans_log(w_id):
    try:
        withdraw_trans_log = ThirdWithdrawTransactionLog.query.filter_by(id=w_id)
        withdraw_trans_log.delete()
        orm.session.commit()
    finally:
        orm.session.close()


def _get_latest_trans(user_id, platform, trans_type=None):
    query = ThirdTransaction.query.filter(
        ThirdTransaction.user_id == user_id, ThirdTransaction.platform == platform).order_by(
        ThirdTransaction.id.desc())
    if trans_type:
        query = query.filter_by(type=trans_type)
    return query.first()


def _calc_current_amount(account, trans):
    trans.curr_balance = convert_yuan_to_fen(account.balance)
    trans.curr_withdraw = convert_yuan_to_fen(account.withdraw)
